package com.info.zhiduoduo.common.utils;

import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.IsoFields;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;

/**
 * 日期转换
 */
public class DateUtil {

	/**
	 * 中国时区, 上海, 北京
	 */
	public final static String TIME_ZONE_CHINA = "Asia/Shanghai";

	/**
	 * yyyy-MM-dd HH:mm:ss
	 */
	public final static String FORMAT_STYLE_1 = "yyyy-MM-dd HH:mm:ss";

	/**
	 * yyyy-MM-dd
	 */
	public final static String FORMAT_STYLE_2 = "yyyy-MM-dd";

	/**
	 * yyyy年MM月dd日
	 */
	public final static String FORMAT_STYLE_3 = "yyyy年MM月dd日";

	/**
	 * yyyyMM
	 */
	public final static String FORMAT_STYLE_4 = "yyyyMM";

	/**
	 * yyyyMMdd
	 */
	public final static String FORMAT_STYLE_5 = "yyyyMMdd";

	/**
	 * yyyy-MM-dd HH:mm
	 */
	public final static String FORMAT_STYLE_6 = "yyyy-MM-dd HH:mm";

	/**
	 * yyyyMMddhhmmss
	 */
	public final static String FORMAT_STYLE_7 = "yyyyMMddHHmmss";

	/**
	 * yyMMdd
	 */
	public final static String FORMAT_STYLE_8 = "yyMMdd";

	/**
	 * yyMM
	 */
	public final static String FORMAT_STYLE_9 = "yyMM";

	/**
	 * yyyy-MM
	 */
	public final static String FORMAT_STYLE_10 = "yyyy-MM";

	/**
	 * yyyyMMddhhmmssSSS
	 */
	public final static String FORMAT_STYLE_11 = "yyyyMMddhhmmssSSS";

	/**
	 * yyyy年MM月
	 */
	public final static String FORMAT_STYLE_12 = "yyyy年MM月";

	public final static String FORMAT_STYLE_13 = "MM";

	public final static String FORMAT_STYLE_14 = "HH:mm";

	/** 周几 , 如果需要显示 "星期一" 直接用localdate的格式化就行 */
	static String[] weeks = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};

	/**
	 * 将Date转换成String
	 *
	 * @param date
	 * @return
	 */
	public static String getString(Date date) {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_STYLE_1);
		return sdf.format(date);
	}

	/**
	 * 获取今天日期
	 */
	public static String getTodayStr() {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_STYLE_5);
		return sdf.format(new Date());
	}

	/**
	 * 将当前时间转换成String
	 *
	 * @param format
	 * @return
	 */
	public static String getNowDateString(String format) {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(new Date());
	}

	/**
	 * 将Date按一定的格式转成成String
	 *
	 * @param date
	 * @param format
	 * @return
	 */
	public static String getStringDate(Date date, String format) {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	/**
	 * 将Date转换成String
	 *
	 * @param date
	 * @param format
	 * @return
	 */
	public static String getString(Date date, String format) {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	/**
	 * 字符转成日期
	 *
	 * @param dateString
	 * @return
	 * @throws ParseException
	 */
	public static Date getDate(String dateString) {
		SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_STYLE_1);
		try {
			return sdf.parse(dateString);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 字符转成日期
	 *
	 * @param dateString
	 * @return
	 * @throws ParseException
	 */
	public static Date formatDate(String dateString,String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		try {
			return sdf.parse(dateString);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 字符转成日期
	 *
	 * @param dateString
	 * @param format
	 * @return
	 * @throws ParseException
	 */
	public static Date getDate(String dateString, String format) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		try {
			return sdf.parse(dateString);
		} catch (ParseException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 获取系统当前时间戳String
	 *
	 * @return
	 */
	public static String getCurrentTimeMillis2String() {
		return new Long(System.currentTimeMillis()).toString();
	}

	/**
	 * 获取系统当前时间----Date
	 *
	 * @return Date
	 */
	public static Date nowTime() {
		return new Date();
	}

	/**
	 * 获取系统当前日期----Date
	 *
	 * @return Date
	 */
	public static Date nowDate() {
		return getStartOfDay(new Date());
	}

	/**
	 * 获取系统当前时间----Timestamp
	 *
	 * @return
	 */
	public static Timestamp getNowTimestamp() {
		Date dt = new Date();
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String nowTime = df.format(dt);
		Timestamp buydate = Timestamp.valueOf(nowTime);
		return buydate;
	}

	/**
	 * @param mins
	 * @return 根据指定分钟数获取距离当前时间的Date时间 -mins 指前几分钟， +mins 后几分钟
	 */
	@SuppressWarnings("deprecation")
	public static Date getSystemTime4AppointMins(int mins) {
		Date nowDate = nowTime();
		nowDate.setMinutes(nowDate.getMinutes() + mins);
		return nowDate;
	}

	/**
	 * @param hours
	 * @return 根据指定小时数获取距离当前时间的Date时间 -hours 指前几小时， +hours 后几小时
	 */
	@SuppressWarnings("deprecation")
	public static Date getSystemTime4AppointHours(int hours) {
		Date nowDate = nowTime();
		nowDate.setHours(nowDate.getHours() + hours);
		return nowDate;
	}

	/**
	 * @param days
	 * @return 根据指定小时数获取距离当前时间的Date时间 -days 指前几天， +days 后几天
	 */
	@SuppressWarnings("deprecation")
	public static Date getSystemTime4AppointDays(int days) {
		Date nowDate = nowTime();
		nowDate.setDate(nowDate.getDate() + days);
		return nowDate;
	}

	/**
	 * 获取2个时间之间的分钟差
	 *
	 * @param startday
	 * @param endday
	 * @return
	 */
	public static int getIntervalMins(Date startday, Date endday) {
		if (startday.after(endday)) {
			Date cal = startday;
			startday = endday;
			endday = cal;
		}
		long sl = startday.getTime();
		long el = endday.getTime();
		long ei = el - sl;
		return (int) (ei / (1000 * 60));
	}

	/**
	 * 获取2个时间之间的天数差
	 *
	 * @param startday
	 * @param endday
	 * @return
	 */
	public static int getIntervalDays(Timestamp startday, Timestamp endday) {
		if (startday.after(endday)) {
			Timestamp cal = startday;
			startday = endday;
			endday = cal;
		}
		long sl = startday.getTime();
		long el = endday.getTime();
		long ei = el - sl;
		return (int) (ei / (1000 * 60 * 60 * 24));
	}

	/**
	 * 获取2个时间之间的天数差,通过localdate 来获取, 相对上一个方法要简单些.
	 *
	 * @param startDate
	 * @param endDate
	 * @return 如果是同一天，则返回0.
	 */
	public static int getIntervalDays(Date startDate, Date endDate) {
		return (int) ChronoUnit.DAYS.between(date2LocalDate(startDate), date2LocalDate(endDate));
	}

	/**
	 * 获取2个时间之间的天数差,
	 *
	 * @param startDate
	 * @param endDate
	 * @return 如果是同一天，则返回0.
	 */
	public static int getIntervalDays(LocalDate startDate, LocalDate endDate) {
		return (int) ChronoUnit.DAYS.between(startDate, endDate);
	}

	/**
	 * 获取2个时间之间的小时差
	 *
	 * @param startday
	 * @param endday
	 * @return
	 */
	public static int getIntervalHours(Timestamp startday, Timestamp endday) {
		if (startday.after(endday)) {
			Timestamp cal = startday;
			startday = endday;
			endday = cal;
		}
		long sl = startday.getTime();
		long el = endday.getTime();
		long ei = el - sl;
		return (int) (ei / (1000 * 60 * 60));
	}

	public static float getIntervalHours_float(Timestamp startday, Timestamp endday) {
		if (startday.after(endday)) {
			Timestamp cal = startday;
			startday = endday;
			endday = cal;
		}
		long sl = startday.getTime();
		long el = endday.getTime();
		long ei = el - sl;
		return (float) (ei / (1000 * 60 * 60));
	}

	/**
	 * 返回某天的0点
	 */
	public static Timestamp getZeroTime(Timestamp time) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(time);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);

		return new Timestamp(cal.getTime().getTime());
	}

	/**
	 * 返回某天的23点
	 */
	public static Timestamp getBigTime(Timestamp time) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(time);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);

		return new Timestamp(cal.getTime().getTime());
	}

	/**
	 * 当前时间的字符串
	 *
	 * @return
	 */
	public static String getNowTimeString() {
		return getString(nowTime());
	}

	public static Timestamp getTimestampByStr(String time) {
		Timestamp ts = new Timestamp(System.currentTimeMillis());
		try {
			ts = Timestamp.valueOf(time);
			return ts;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取相差指定日期
	 *
	 * @param time ：指定日期
	 * @param days ： days可正可负，负为指定日期前，正为指定日期后
	 * @return
	 */
	public static Timestamp getTimeAdd(Timestamp time, int days) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(time);
		cal.add(Calendar.DAY_OF_YEAR, days);
		return new Timestamp(cal.getTime().getTime());
	}

	/**
	 * 获取距离指定时间的指定日期
	 *
	 * @param date 指定时间
	 * @param days days可正可负，负为指定日期前，正为指定日期后
	 * @return
	 */
	public static Date getDayChange(Date date, int days) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(date);
		cal.add(Calendar.DAY_OF_YEAR, days);
		return cal.getTime();
	}

	/**
	 * 获取相差指定日期
	 *
	 * @param time   ：指定日期
	 * @param months ： days可正可负，负为指定日期前，正为指定日期后
	 * @return
	 */
	public static Timestamp getMonthAdd(Timestamp time, int months) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(time);
		cal.add(Calendar.MONTH, months);
		cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));

		return new Timestamp(cal.getTime().getTime());
	}

	/**
	 * 判断给定日期是否已经超时 判断年，月，日
	 *
	 * @param time ：指定日期
	 * @return 超时=true，未超时=false
	 */
	public static Boolean judgeTime(Timestamp time) {
		Timestamp nowTime = new Timestamp((new Date()).getTime());
		nowTime = getBigTime(nowTime);
		time = getBigTime(time);
		/*
		 * GregorianCalendar calStart = new GregorianCalendar();
		 * calStart.setTime(time); GregorianCalendar calNow = new
		 * GregorianCalendar(); calNow.setTime(nowTime);
		 */
		return nowTime.after(time);
	}

	/**
	 * 判断给定日期是否已经超时 判断年，月，日
	 *
	 * @param date
	 * @return
	 */
	public static Boolean judgeTimeByDate(Date date) {
		Date now = nowTime();
		return now.after(date);
	}

	//获取上个工作日
	public static Date getPreviousWorkingDay(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int dayOfWeek;
		do {
			cal.add(Calendar.DAY_OF_MONTH, -1);
			dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		} while (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY);

		return cal.getTime();
	}

	/**
	 * 获得上月1号的日期
	 */
	public static Date getLastMonthBeginDate() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) - 1);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获得上个月最后一天的日期
	 */
	public static Date getLastMonthEndDate() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.DAY_OF_MONTH, 0);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
	}

	/**
	 * 获得这个月最后一天的日期
	 */
	public static Date getThisMonthEndDate() {
		Calendar cal = Calendar.getInstance();
		// 当月最大天数
		int a = cal.getActualMaximum(Calendar.DATE);
		cal.set(Calendar.DAY_OF_MONTH, a);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
	}

	/**
	 * 获得当月1号的日期
	 */
	public static Date getThisMonthBeginDate() {
		Calendar cal = Calendar.getInstance();
		// 当月最小天数
		int a = cal.getActualMinimum(Calendar.DATE);
		cal.set(Calendar.DAY_OF_MONTH, a);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获得时间中年，月，日单个值
	 */
	public static int getMonthFromDate(Date date, int type) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(date);
		int monthNow = cal.get(type);

		return monthNow;
	}

	/**
	 * 获取年龄
	 *
	 * @param year
	 * @param month
	 * @param day
	 * @return
	 */
	public static int getAge(int year, int month, int day) {
		try {
			// 年龄
			int age = getNowYear();
			age = age - year;
			// 日本年龄满一年才是一岁
			age = age - 1;
			if (0 > age) {
				age = 0;
			}
			if (getNowMonth() > month) {
				// 当前月大于出生月，年龄加1
				age++;
			} else if (getNowMonth() == month) {
				// 当前日等于出生月,并且日大于生日
				if (getNowDay() > day) {
					age++;
				}
			}
			return age;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前季度
	 *
	 * @return
	 */
	public static int getNowYear() {
		try {
			// 当前年
			return Calendar.getInstance().get(Calendar.YEAR);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前季度
	 *
	 * @return
	 */
	public static int getYear(Date date) {
		try {
			// 当前年
			Calendar instance = Calendar.getInstance();
			instance.setTime(date);
			return instance.get(Calendar.YEAR);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前季度
	 *
	 * @return
	 */
	public static int getNowQuater() {
		try {
			// 当前季度
			return getQuarterOfMonth(getNowMonth());
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前季度
	 *
	 * @return
	 */
	public static int getQuater(Date date) {
		try {
			// 当前季度
			return getQuarterOfMonth(getMonth(date));
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前月
	 *
	 * @return
	 */
	public static int getNowMonth() {
		try {
			// 当前月
			return Calendar.getInstance().get(Calendar.MONTH) + 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前月
	 *
	 * @return
	 */
	public static int getMonth(Date date) {
		try {
			// 当前月
			Calendar instance = Calendar.getInstance();
			instance.setTime(date);
			return instance.get(Calendar.MONTH) + 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前日
	 *
	 * @return
	 */
	public static int getNowDay() {
		try {
			// 当前日
			return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得当前日
	 *
	 * @return
	 */
	public static int getDay(Date date) {
		try {
			// 当前日
			Calendar instance = Calendar.getInstance();
			instance.setTime(date);
			return instance.get(Calendar.DAY_OF_MONTH);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 取得指定日期所在月份开始时间
	 *
	 * @return
	 */
	public static Date getDateMonthBeginDate(Date date) {
		Calendar cal = Calendar.getInstance();
		int a = cal.getActualMinimum(Calendar.DATE);
		cal.setTime(date);
		cal.set(Calendar.MONTH, date.getMonth());
		cal.set(Calendar.DAY_OF_MONTH, a);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 取得指定日期所在月份结束时间
	 *
	 * @return
	 */
	public static Date getDateMonthEndDate(Date date) {
		Calendar cal = Calendar.getInstance();
		int a = cal.getActualMaximum(Calendar.DATE);
		cal.setTime(date);
		cal.set(Calendar.MONTH, date.getMonth());
		cal.set(Calendar.DAY_OF_MONTH, a);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
	}

	/**
	 * 现在距离指定时间还有多少小时
	 *
	 * @param appointedTime
	 * @return
	 */
	public static int getHourByAppointedTime(Date appointedTime) {
		long now = nowTime().getTime();
		long at = appointedTime.getTime();
		long ei = at - now;
		return (int) (ei / (1000 * 60 * 60));
	}

	/**
	 * 与现在的时间相差几分钟
	 *
	 * @param appointedTime
	 * @return
	 */
	public static int getminsByAppointedTime(Date appointedTime) {
		long now = nowTime().getTime();
		long at = appointedTime.getTime();
		long ei = now - at;
		return (int) (ei / (1000 * 60));
	}

	/**
	 * 与现在的时间相差几分钟
	 *
	 * @param appointedTime
	 * @return
	 */
	public static int getminsByAppointedTimestamp(Timestamp appointedTime) {
		long now = nowTime().getTime();
		long at = appointedTime.getTime();
		long ei = now - at;
		return (int) (ei / (1000 * 60));
	}

	/**
	 * 与现在的时间相差几分钟
	 *
	 * @param appointedTime
	 * @param type          1:分钟 2秒
	 * @return
	 */
	public static int getNumsByAppointedTimestamp(Timestamp appointedTime, int type) {
		long now = nowTime().getTime();
		long at = appointedTime.getTime();
		long ei = now - at;
		if (type == 1) {
			return (int) (ei / (1000 * 60));
		} else if (type == 2) {
			return (int) (ei / 1000);
		}
		return 0;
	}

	public static String formatToYYYYMMDD(Date date) {
		if (date == null) {
			return "";
		}
		String result = "";
		try {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			result = format.format(date);
		} catch (Exception e) {
			return "";
		}
		return result;
	}

	public static String formatToYYYYMMDD2(Date date) {
		if (date == null) {
			return "";
		}
		String result = "";
		try {
			SimpleDateFormat format = new SimpleDateFormat(FORMAT_STYLE_5);
			result = format.format(date);
		} catch (Exception e) {
			return "";
		}
		return result;
	}

	public static Date parseDate(String dateStr, String pattern) {
		Date date = null;
		if (!StringUtils.isEmpty(dateStr)) {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			try {
				date = sdf.parse(dateStr);
			} catch (ParseException e) {
			}
		}
		return date;
	}

	public static Date addSecond(Date date, int seconds) {
		return localDateTime2Date(date2LocalDateTime(date).plus(seconds, ChronoUnit.SECONDS));
	}

	public static Date addMinute(Date date, int minutes) {
		return localDateTime2Date(date2LocalDateTime(date).plus(minutes, ChronoUnit.MINUTES));
	}

	public static Date addHour(Date date, int hours) {
		return localDateTime2Date(date2LocalDateTime(date).plus(hours, ChronoUnit.HOURS));
	}

	public static Date addDay(Date date, int days) {
		return localDate2Date(date2LocalDate(date).plusDays(days));
	}

	public static Date addWeek(Date date, int weeks) {
		return localDate2Date(date2LocalDate(date).plusWeeks(weeks));
	}

	public static Date addMonth(Date date, int months) {
		return localDate2Date(date2LocalDate(date).plusMonths(months));
	}

	public static Date addYear(Date date, int years) {
		return localDate2Date(date2LocalDate(date).plusYears(years));
	}

	/**
	 * 按工作日,增加天数,跳过周六,周日
	 *
	 * @param date
	 * @param days 可正可负.
	 * @return 返回纯日期, 会丢失时分秒部分
	 */
	public static Date addWorkDay(Date date, int days) {
		int abs = Math.abs(days);
		int oneDay = abs / days;
		LocalDate from = date2LocalDate(date);
		for (int i = 0; i < abs; i++) {
			from = from.plusDays(oneDay);
			// 跳过周六,周日
			while (from.getDayOfWeek().getValue() >= 6) {
				from = from.plusDays(oneDay);
			}
		}
		return localDate2Date(from);
	}

	/**
	 * 判断是否是周末
	 *
	 * @param date
	 * @return
	 */
	public static boolean isWeekend(Date date) {
		int value = date2LocalDate(date).getDayOfWeek().getValue();
		return value == 6 || value == 7;
	}

	/**
	 * localDate转Date
	 */
	public static Date localDate2Date(LocalDate localDate) {
		ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
		Instant instant1 = zonedDateTime.toInstant();
		Date from = Date.from(instant1);
		return from;
	}

	/**
	 * localDateTime转Date
	 */
	public static Date localDateTime2Date(LocalDateTime localDateTime) {
		ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
		Instant instant1 = zonedDateTime.toInstant();
		Date from = Date.from(instant1);
		return from;
	}

	/**
	 * Date 转 localDate
	 */
	public static LocalDate date2LocalDate(Date date) {
		Instant instant = date.toInstant();
		ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
		LocalDate localDate = zdt.toLocalDate();
		return localDate;
	}

	/**
	 * Date 转 localDateTime
	 */
	public static LocalDateTime date2LocalDateTime(Date date) {
		Instant instant = date.toInstant();
		ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
		LocalDateTime localDateTime = zdt.toLocalDateTime();
		return localDateTime;
	}

	//获取月第一天
	public static Date getStartDayOfMonth(String date) {
		LocalDate now = LocalDate.parse(date);
		return getStartDayOfMonth(now);
	}

	public static Date getStartDayOfMonth(Date date) {
		return getStartDayOfMonth(date2LocalDate(date));
	}

	public static Date getStartDayOfMonth(LocalDate date) {
		LocalDate now = date.with(TemporalAdjusters.firstDayOfMonth());
		return localDate2Date(now);
	}

	//获取月最后一天
	public static Date getEndDayOfMonth(String date) {
		LocalDate localDate = LocalDate.parse(date);
		return getEndDayOfMonth(localDate);
	}

	//获取月最后一天
	public static Date getEndDayOfMonth(Date date) {
		return getEndDayOfMonth(date2LocalDate(date));
	}

	public static Date getEndDayOfMonth(LocalDate date) {
		LocalDate now = date.with(TemporalAdjusters.lastDayOfMonth());

		Date.from(now.atStartOfDay(ZoneId.systemDefault()).plusDays(1L).minusNanos(1L).toInstant());
		return localDate2Date(now);
	}

	//获取周第一天
	public static Date getStartDayOfWeek(String date) {
		LocalDate now = LocalDate.parse(date);
		return getStartDayOfWeek(now);
	}

	public static Date getStartDayOfWeek(TemporalAccessor date) {
		TemporalField fieldISO = WeekFields.of(Locale.CHINA).dayOfWeek();
		LocalDate localDate = LocalDate.from(date);
		localDate = localDate.with(fieldISO, 1);
		return localDate2Date(localDate);
	}

	//获取周最后一天
	public static Date getEndDayOfWeek(String date) {
		LocalDate localDate = LocalDate.parse(date);
		return getEndDayOfWeek(localDate);
	}

	public static Date getEndDayOfWeek(TemporalAccessor date) {
		TemporalField fieldISO = WeekFields.of(Locale.CHINA).dayOfWeek();
		LocalDate localDate = LocalDate.from(date);
		localDate = localDate.with(fieldISO, 7);
		return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1L).minusNanos(1L).toInstant());
	}

	//一天的开始
	public static Date getStartOfDay(String date) {
		LocalDate localDate = LocalDate.parse(date);
		return getStartOfDay(localDate);
	}

	//一天的开始
	public static Date getStartOfDay(Date date) {
		LocalDate localDate = DateUtil.date2LocalDate(date);
		return getStartOfDay(localDate);
	}

	public static Date getStartOfDay(TemporalAccessor date) {
		LocalDate localDate = LocalDate.from(date);
		return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
	}

	//一天的结束
	public static Date getEndOfDay(String date) {
		LocalDate localDate = LocalDate.parse(date);
		return getEndOfDay(localDate);
	}

	//一天的结束
	public static Date getEndOfDay(Date date) {
		LocalDate localDate = date2LocalDate(date);
		return getEndOfDay(localDate);
	}

	public static Date getEndOfDay(TemporalAccessor date) {
		LocalDate localDate = LocalDate.from(date);
		return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1L).minusNanos(1L).toInstant());
	}

	public static Date getTomorrow() {
		LocalDate localDate = date2LocalDate(new Date()).plusDays(1);
		return localDate2Date(localDate);
	}

	public static Date getYesterday() {
		LocalDate localDate = date2LocalDate(new Date()).minusDays(1);
		return localDate2Date(localDate);
	}

	/**
	 * 季度的第一天
	 */
	public static Date getQuarterBeginDate(Date date) {
		Quarter quarter = getQuarterOfDate(date);
		switch (quarter) {
			case FIRST:
				return getStartDayOfMonth(LocalDate.now().withMonth(1));
			case SECOND:
				return getStartDayOfMonth(LocalDate.now().withMonth(4));
			case THIRD:
				return getStartDayOfMonth(LocalDate.now().withMonth(7));
			case FOURTH:
				return getStartDayOfMonth(LocalDate.now().withMonth(10));
			default:
				return getStartDayOfMonth(LocalDate.now().withMonth(1));
		}
	}

	/**
	 * 获取当前时间所在季度的第几个月,第一个月从1开始。返回月份
	 * The input 2011-11-10，int=1 will return 10.
	 * The input 2011-11-11，int=2 will return 11.
	 * The input 2011-11-11，int=3 will return 12.
	 */
	public static int getQuarterNumMonth(Date date, int no) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int currentMonth = cal.get(Calendar.MONTH) + 1;

		int month = currentMonth;
		if (currentMonth >= 1 && currentMonth <= 3) {
			month = 0 + no;
		} else if (currentMonth >= 4 && currentMonth <= 6) {
			month = 3 + no;
		} else if (currentMonth >= 7 && currentMonth <= 9) {
			month = 6 + no;
		} else if (currentMonth >= 10 && currentMonth <= 12) {
			month = 9 + no;
		}
		return month;
	}

	/**
	 * 季度的最后一天
	 */
	public static Date getQuarterEndDate(Date date) {
		Quarter quarter = getQuarterOfDate(date);
		switch (quarter) {
			case FIRST:
				return getEndDayOfMonth(LocalDate.now().withMonth(3));
			case SECOND:
				return getEndDayOfMonth(LocalDate.now().withMonth(6));
			case THIRD:
				return getEndDayOfMonth(LocalDate.now().withMonth(9));
			case FOURTH:
				return getEndDayOfMonth(LocalDate.now().withMonth(12));
			default:
				return getEndDayOfMonth(LocalDate.now().withMonth(3));
		}
	}

	/**
	 * 获取 当前为周几, 显示为"周一"
	 *
	 * @param date
	 * @return
	 */
	public static String getWeekString(LocalDate date) {
		int value = date.getDayOfWeek().getValue();
		return weeks[value - 1];
	}

	/**
	 * 获取 当前为星期几, 显示为"星期一"
	 *
	 * @param date
	 * @return
	 */
	public static String getWeekString2(LocalDate date) {
		return date.getDayOfWeek().getDisplayName(TextStyle.FULL_STANDALONE, Locale.CHINA);
	}

	/**
	 * 两个时间之间相差距离多少天
	 *
	 * @param one 时间参数 1：
	 * @param two 时间参数 2：
	 * @return 相差天数
	 */
	public static long getDistanceDays(Date one, Date two) throws Exception {
		long days = 0;
		long time1 = one.getTime();
		long time2 = two.getTime();
		long diff;
		if (time1 < time2) {
			diff = time2 - time1;
		} else {
			diff = time1 - time2;
		}
		days = diff / (1000 * 60 * 60 * 24);
		return days;
	}

	/**
	 * 两个时间相差距离多少天多少小时多少分多少秒
	 *
	 * @param one
	 * @param two
	 * @return long[] 返回值为：{天, 时, 分, 秒}
	 */
	public static long[] getDistanceTimes(Date one, Date two) {
		long day = 0;
		long hour = 0;
		long min = 0;
		long sec = 0;
		long time1 = one.getTime();
		long time2 = two.getTime();
		long diff;
		if (time1 < time2) {
			diff = time2 - time1;
		} else {
			diff = time1 - time2;
		}
		day = diff / (24 * 60 * 60 * 1000);
		hour = (diff / (60 * 60 * 1000) - day * 24);
		min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
		sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
		long[] times = {day, hour, min, sec};
		return times;
	}

	/**
	 * 两个时间相差距离多少天多少小时多少分多少秒
	 *
	 * @param one
	 * @param two
	 * @return String 返回值为：xx天xx小时xx分xx秒
	 */
	public static String getDistanceTime(Date one, Date two) {
		long day = 0;
		long hour = 0;
		long min = 0;
		long sec = 0;
		long time1 = one.getTime();
		long time2 = two.getTime();
		long diff;
		if (time1 < time2) {
			diff = time2 - time1;
		} else {
			diff = time1 - time2;
		}
		day = diff / (24 * 60 * 60 * 1000);
		hour = (diff / (60 * 60 * 1000) - day * 24);
		min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
		sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
		return day + "天" + hour + "小时" + min + "分" + sec + "秒";
	}

	public static Date getEpochTime() {
		return new Date(0);
	}

	/**
	 * 如果日期为null，返回默认的java 起始日期，1970-1-1. 不为null，返回原始值
	 *
	 * @param date
	 * @return
	 */
	public static Date defaultInitial(Date date) {
		if (date == null) return getEpochTime();
		return date;
	}

	/**
	 * 如果日期为null，返回当前时间. 不为null，返回原始值
	 *
	 * @param date
	 * @return
	 */
	public static Date defaultNow(Date date) {
		if (date == null) return nowTime();
		return date;
	}

	/**
	 * 如果日期为null，返回一个非常久之后的时间. 不为null，返回原始值
	 *
	 * @param date
	 * @return
	 */
	public static Date defaultEndless(Date date) {
		if (date == null) return DateUtil.parseDate("9999-12-31", DateUtil.FORMAT_STYLE_2);
		return date;
	}

	/**
	 * 检查指定的时间是否过期（对比当前时间）
	 *
	 * @param date
	 * @return true：指定的时间小于当前时间，说明已过期。false：指定时间大于等于当前时间，未过期。如果任何一个参数传null，返回false。
	 */
	public static boolean isExpired(Date date) {
		return isExpired(date, DateUtil.nowTime());
	}

	/**
	 * 检查指定的时间是否过期（对比compareTo的时间）。
	 *
	 * @param target    指定的时间
	 * @param compareTo 对比的时间
	 * @return true：指定的时间小于对比的时间，说明已过期。false：指定时间大于等于对比的时间，未过期。如果任何一个参数传null，返回false。
	 */
	public static boolean isExpired(Date target, Date compareTo) {
		if (target == null || compareTo == null) return false;
		return target.before(compareTo);
	}

	/**
	 * 季度枚举值,1,2,3,4
	 */
	public enum Quarter {
		FIRST(1), SECOND(2), THIRD(3), FOURTH(4);

		Quarter(int value) {
			this.value = value;
		}

		public int value;
	}

	/**
	 * 获取指定日期的当前季度
	 *
	 * @param date
	 * @return
	 */
	public static Quarter getQuarterOfDate(Date date) {
		if (date == null) return null;

		LocalDate localDate = date2LocalDate(date);

		if (localDate.isBefore(localDate.with(Month.APRIL).withDayOfMonth(1))) {
			return Quarter.FIRST;
		} else if (localDate.isBefore(localDate.with(Month.JULY).withDayOfMonth(1))) {
			return Quarter.SECOND;
		} else if (localDate.isBefore(localDate.with(Month.OCTOBER).withDayOfMonth(1))) {
			return Quarter.THIRD;
		} else {
			return Quarter.FOURTH;
		}
	}

	/**
	 * @param month 1-12
	 * @return 季度值
	 */
	public static int getQuarterOfMonth(int month) {
		LocalDate localDate = LocalDate.now().with(Month.of(month));
		return localDate.get(IsoFields.QUARTER_OF_YEAR);
	}

	/**
	 * 获取指定日期的所在季度的月份值，如第一季度“1，2，3”
	 *
	 * @param date
	 * @return
	 */
	public static String getQuarterMonthStrOfDate(Date date) {
		Quarter quarter = getQuarterOfDate(date);
		if (quarter == null) return "";

		switch (quarter) {
			case FIRST:
				return "1,2,3";
			case SECOND:
				return "4,5,6";
			case THIRD:
				return "7,8,9";
			case FOURTH:
				return "10,11,12";
			default:
				return "";
		}
	}

	/**
	 * 日期转换成字符串
	 *
	 * @param format 格式：例如yyyy-MM-dd HH:mm:ss或yyyy-MM-dd，按照自己的需求来
	 * @param date   日期
	 * @return 返回String
	 */
	public static String DateToStr(String format, Date date) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
		return simpleDateFormat.format(date);
	}

	/**
	 * 字符串转换成日期
	 *
	 * @param format 格式：例如yyyy-MM-dd HH:mm:ss或yyyy-MM-dd，按照自己的需求来
	 * @param str    日期
	 * @return 返回Date
	 */
	public static Date StrToDate(String format, String str) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
		Date date = null;
		try {
			date = simpleDateFormat.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	/**
	 * 获取指定日期
	 *
	 * @param format 格式：例如yyyy-MM-dd HH:mm:ss或yyyy-MM-dd，按照自己的需求来
	 * @param date   日期
	 * @param day    正：向后几天；负：向前几天
	 * @return 返回String
	 */
	public static String getAppointDate(String format, Date date, int day) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, day);
		date = calendar.getTime();
		return simpleDateFormat.format(date);
	}

	/**
	 * 获取指定时间段内所有日期
	 *
	 * @param beginDate 开始日期 格式：yyyy-MM-dd
	 * @param endDate   结束时间 格式：yyyy-MM-dd
	 * @return 返回List<String>
	 * @throws Exception 异常
	 */
	public static List<String> getAppointTimeSlotDate(String beginDate, String endDate) throws Exception {
		List<String> dateList = new ArrayList<>();
		SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
		long startTime = date.parse(beginDate).getTime();
		long endTime = date.parse(endDate).getTime();
		long day = 1000 * 60 * 60 * 24;
		for (long i = startTime; i <= endTime; i += day) {
			System.out.println(date.format(new Date(i)));
			dateList.add(date.format(new Date(i)));
		}
		return dateList;
	}

	/**
	 * 比较两个时间大小（结束时间大于开始时间返回true）
	 *
	 * @param beginTime 开始时间
	 * @param endTime   结束时间
	 * @return 返回 boolean
	 */
	public static boolean compareToTime(String beginTime, String endTime) throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date bt = sdf.parse(beginTime);
		Date et = sdf.parse(endTime);
		if (bt.before(et)) {
			return true;
		} else {
			if (beginTime.equals(endTime)) {
				return true;
			} else {
				return false;
			}
		}
	}

	/**
	 * 获取一个时间段内一共有几天
	 *
	 * @param date1 开始时间
	 * @param date2 结束时间
	 * @return 返回
	 */
	public static int differentDays(Date date1, Date date2) {
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date1);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(date2);
		int day1 = cal1.get(Calendar.DAY_OF_YEAR);
		int day2 = cal2.get(Calendar.DAY_OF_YEAR);
		int year1 = cal1.get(Calendar.YEAR);
		int year2 = cal2.get(Calendar.YEAR);
		if (year1 != year2)   //同一年
		{
			int timeDistance = 0;
			for (int i = year1; i < year2; i++) {
				if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)    //闰年
				{
					timeDistance += 366;
				} else    //不是闰年
				{
					timeDistance += 365;
				}
			}
			return timeDistance + (day2 - day1);
		} else    //不同年
		{
			return day2 - day1;
		}
	}

	/**
	 * 比较两个时间相差多少时间
	 *
	 * @param oldTime
	 * @param newTime
	 * @return
	 * @throws ParseException
	 */
	public static long differMinute(String oldTime, String newTime) {
		try {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			long NTime = df.parse(newTime).getTime();
			//从对象中拿到时间
			long OTime = df.parse(oldTime).getTime();
			return (NTime - OTime) / 1000 / 60;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 判断
	 * 是否 符合周期时间
	 *
	 * @return
	 */
	public static boolean isDateCycle(Date date, int year) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.YEAR, year);
		Date time = cal.getTime();
		Date nowDate = new Date(); // 获取 当前时间
		return nowDate.after(time);
	}

	/**
	 * 计算2个日期相差多少整年
	 * 列：2016-02-02  ~  2017-03-02 相差 1 年
	 *
	 * @param fromDate
	 * @param toDate
	 * @return
	 */
	public static int yearDiffPeriod(Date fromDate, Date toDate) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(fromDate);
		cal.add(Calendar.DATE, -1);

		int i = 0;
		for (i = 0; i < 100; i++) {
			cal.add(Calendar.YEAR, 1);
			Date time = cal.getTime();
			if (time.after(toDate)) {
				break;
			}
		}
		return i;
	}

	public static Date getYearCycleEndDate(Date date, int year) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.YEAR, year + 1);
		cal.add(Calendar.DAY_OF_MONTH, -1);
		Date startTime = cal.getTime();
		return startTime;
	}

	public static Date getYearCycleStartDate(Date date, int year) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.YEAR, year);
		Date startTime = cal.getTime();
		return startTime;
	}

	public static String getYearCycleStr(Date startTime,Date endTime){
		String startStr = DateToStr(DateUtil.FORMAT_STYLE_2, startTime);
		String endStr = DateToStr(DateUtil.FORMAT_STYLE_2, endTime);
		return startStr + "至" + endStr;
	}

	/**
	 * 计算 年份周期
	 * 例如 2019-02-03
	 * 1 周期 2019-02-03至2020-02-02
	 * 2 周期 2020-02-03至2021-02-02
	 *
	 * @param date 日期
	 * @param year 第几年的周期
	 * @return
	 */
	public static String yearCycle(Date date, int year) {

		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.YEAR, year - 1);
		Date startTime = cal.getTime(); // 开始周期年
		if (year == 1) {
			cal.add(Calendar.YEAR, 1);
		} else {
			cal.add(Calendar.YEAR, year - 1);
		}
		cal.add(Calendar.DAY_OF_MONTH, -1);
		Date endTime = cal.getTime(); // 结束周期年
		String startStr = DateToStr(DateUtil.FORMAT_STYLE_2, startTime);
		String endStr = DateToStr(DateUtil.FORMAT_STYLE_2, endTime);

		return startStr + "至" + endStr;
	}

	public static boolean isSameMonth(Date one, Date two) {
		if (one == null || two == null) return false;
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(one);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(two);
		return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
	}

	public static boolean isSameDay(Date one, Date two) {
		if (one == null || two == null) return false;
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(one);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(two);
		return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * 获取指定时间往前12个月的月份开始日期
	 * 2022-02-21 return 2021-03-01
	 */
	public static Date getLatest12Month(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -11);//11个月前
		return getDateMonthBeginDate(calendar.getTime());
	}

	/**
	 * 判断时间是否在某个时间段内[startTime, endTime]区间，注意时间格式要一致
	 *
	 * @param time 时间
	 * @param startTime 开始时间段 HH:mm格式
	 * @param endTime 结束时间段 HH:mm格式
	 * @return
	 */
	public static boolean isInTimeRange(String time, String startTime, String endTime) {
		int set = Integer.valueOf(time.replaceAll(":", ""));
		int begin = Integer.valueOf(startTime.replaceAll(":", ""));
		int end = Integer.valueOf(endTime.replaceAll(":", ""));
		if (begin > end) {
			return set < end || set > begin;
		} else {
			return set > begin && set < end;
		}
	}

	public static Date getLastDayOfQuarter(int year, int quarter) {

		int lastMonth = quarter * 3 - 1;

		// 根据月获取开始时间
		// 根据月获取开始时间
		Calendar cal = Calendar.getInstance();

		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, lastMonth);
		cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));

		cal.set(Calendar.HOUR, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);

		return cal.getTime();

	}
	/**
	 * 将Date转换成Stringy格式yyy-MM-dd
	 *
	 * @param date
	 * @return
	 */
	public static String getStrings(Date date) {
		// 日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_STYLE_2);
		return sdf.format(date);
	}
	/**
	 * 获取当前时间前N分钟
	 * @param
	 * @return
	 */
	public static Date getCurrentTime(int n){
		Calendar beforeTime = Calendar.getInstance();
		beforeTime.add(Calendar.MINUTE, -n);// 3分钟之前的时间
		Date beforeD = beforeTime.getTime();
		return beforeD;
	}

}
